package tagsFilesClientDataBase;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import client_AutoTag.LoadingClass;
import client_prefernceGui.PreferenceGUI;

/**
 * TagFilesDB - Data Base Client include Tag Table, File Table
 * 				and services function that handle with many-to-many relationship 
 * 
 * --Singleton--
 * 
 * @author Orit && Yoav
 *
 */
public class TagFilesDB {
    static SessionFactory sessionFactory; 
	static Session session;

	 
	//--Private constructor TagFilesDB-//
    private TagFilesDB() { 
    }
	/**
	* 
	* SingletonHolder is loaded on the first execution of Singleton.getInstance() 
	* or the first access to SingletonHolder.INSTANCE, not before.
	*/
	private static class TagFilesDBHolder
	{
		private final static TagFilesDB INSTANCE = new TagFilesDB();
	}
	/**
	 * return an instance of  Tag Files Data Base
	 * @return TagFilesDB instance
	 */
	public static TagFilesDB getInstance()
	{
		return TagFilesDBHolder.INSTANCE;
	}
	//----------------------------------------------------------------------------//
	
	/**
	 * open session 
	 * if the session is close open the session 
	 */
	public void openSession(){
		if (sessionFactory==null){
			sessionFactory = new Configuration().configure().buildSessionFactory(); 
		}
		if (session == null){
			session = sessionFactory.openSession();
			return;
		}
		
		if (!session.isConnected()){
			sessionFactory = new Configuration().configure().buildSessionFactory(); 			
		}
		if (!session.isOpen()){
			session = sessionFactory.openSession();
		}
	}
	
	/**
	 * remove all client files in Data base
	 */
	public void removeAllFiles(){
		openSession();
		Query query = session.createQuery("from ClientFile");
		List<ClientFile> tagList = query.list();
		Iterator<ClientFile> it=tagList.iterator();
		while (it.hasNext()){
			ClientFile tag=it.next();
			if (tag != null){ //the file exist so we must remove it from DB
				session.delete(tag);
				System.out.println("tag remove with ID = "+ tag.getFileId());
				
			}			
		}
		session.flush();
		
	}

	/**
	 * remove all tags in data base
	 */
	public void removeAllTags(){
		openSession();
		Query query = session.createQuery("from Tag");
		List<Tag> tagList = query.list();
		Iterator<Tag> it=tagList.iterator();
		while (it.hasNext()){
			Tag tag=it.next();
			if (tag != null){ //the file exist so we must remove it from DB
				session.delete(tag);	
				System.out.println("tag remove with ID = "+ tag.getTagId());
				
			}			
		}
		session.flush();
		
	}	  
	
	/**
	 * search all the files By tag name 
	 * @param tagName
	 * @return list of files
	 */
	public List<String> searchByTag(String tagName){
		ArrayList<String> fileList=new ArrayList<String> ();
		Tag tag = findTag(tagName);
		 if (tag!=null) {
			 for (ClientFile cf: tag.getFiles()){
				 fileList.add(cf.getFileName());
			 }
		 }
		return fileList;
	}
	
	/**
	 * return list of files by query (list of tags)
	 * @param tagName a query
	 * @return of files 
	 */
	public List<String> queryByTags(String tagName){
		ArrayList<String> fileList=new ArrayList<String> ();
		openSession();
		Query query = session.createQuery("from ClientFile file join file.tags tag Where tag.tagName='start with:dr' or tag.tagName ='recently modify'");
		List<Object[]> list = query.list();
		Iterator<Object[]> it=list.iterator();
		while (it.hasNext()){
		     Object[] obj = it.next();
		     System.out.println(((ClientFile)obj[0]).getFileName());
		     fileList.add(((ClientFile)obj[0]).getFileName());
		     }
	     System.out.println("done");
		return fileList;
	}
	
	/**
	 * add one tag method to Data base of methods 
	 * @param tagMethodName	the name of method
	 */
	public void addTagMethodToDB(String tagMethodName){
			openSession();
			boolean ans = isTagMethodExist(tagMethodName);
			if (ans==false) { //if the method not found add him to data base
				TagMethod method = new TagMethod();
				method.setPath(tagMethodName);
				session.save(method);
				session.flush();
			}
			
		}
	 
	/**
	 * add one file To data base
	 * @param fileName - name of the file 
	 */
	 public void addFileToDB(String fileName){
		System.out.println("open session");
		openSession();
		System.out.println("find file");
		ClientFile file = findFile(fileName);
		boolean isExistFile=true;
		if (file==null) { //if the file not found add him to data base
			System.out.println("file is not exist add him to DB");
			isExistFile = false;
			file = new ClientFile();
			file.setFileName(fileName);
			System.out.println("save file");
			session.save(file);	
			System.out.println("flush");
			session.flush();
			System.out.println("after flush");
		}
		if (!isExistFile){
			System.out.println("add tags to file");
			addTagsToFile(fileName); //update the file's tag 
		}
		PreferenceGUI.addItemsToTagsTable();
	}
	 
	/**
	 *  remove file From Data Base
	 * @param fileName - the ame of the file we want to remove
	 */
	public void removeFileFromDB(String fileName){
		openSession();
		//removeTagsFromTheFile(fileName);
		ClientFile file = findFile(fileName);
		if (file!=null) {
			file.getTags().clear();
			session.update(file);
			session.flush();
			
			removeTagsFromTheFile(file);
			
			session.delete(file);
			session.flush();
		}
		removeTagsFromDB();
		PreferenceGUI.addItemsToTagsTable();
	}
		
	private void removeTagsFromTheFile(ClientFile file) {
		Query query = session.createQuery("from Tag");
		List<Tag> tagList = query.list();
		Iterator<Tag> it=tagList.iterator();
		while (it.hasNext()){
			Tag tag=it.next();
			if (tag != null && tag.getFiles().contains(file)){	
				tag.getFiles().remove(file);
				session.update(tag);
			}			
		}
		session.flush();						
	}
	
	public List<String> searchByQuery(String tagName){
		ArrayList<String> fileList=new ArrayList<String> ();
		openSession();
		Query query = session.createQuery("from ClientFile file join file.tags tag Where tag.tagName='start with:dr' and tag.tagName ='recently modify'");
		List<Object[]> list = query.list();
		Iterator<Object[]> it=list.iterator();
		while (it.hasNext()){
		     Object[] obj = it.next();
		     System.out.println(((ClientFile)obj[0]).getFileName());
		     fileList.add(((ClientFile)obj[0]).getFileName());
		     }
	     System.out.println("done");
		return fileList;
	}

	
	private void removeTagsFromDB() {
		Query query = session.createQuery("from Tag");
		List<Tag> tagList = query.list();
		Iterator<Tag> it=tagList.iterator();
		while (it.hasNext()){
			Tag tag=it.next();
			if (tag != null && tag.getFiles().size()==0){	
				tag.getFiles().clear();
				session.delete(tag);
			}			
		}
		session.flush();				
	}
	
	/*
	 * add the tags to the list of new file  
	 * @param fileName- the name of the new file 
	 */
	private void addTagsToFile(String fileName) {
		LoadingClass updates = new LoadingClass();	
		List<String> list = getTagMethodList();
		for (String m: list){ 
		//scan all the method in the list and update the new file 
			updates.setPlugInPath(m);
			updates.dynamicClassLoading(fileName);
		}
	}
	
	/**
	 * add a new Tag To the tag table in the data base
	 * @param tagName
	 * @param fileName
	 */
	public void addTagToDB(String tagName,String fileName){
		openSession();
		Tag tag = findTag(tagName);
		if (tag==null) { //the tag is not exist -> create new one 
			tag = new Tag();
			tag.setTagName(tagName);
			session.save(tag);		
			session.flush();
		}
		findFileOfTag(fileName,tag);
	
	 }	
	
	/*
	 * find the tag by it's name 
	 * @param tagName
	 * return the Appropriate Tag object
	 */
	private Tag findTag(String tagName){
		openSession();
		Query query = session.createQuery("from Tag Where tag_name='"+ tagName+ "'");
		List<Tag> list = query.list();
		Tag tag = new Tag();
		Iterator<Tag> it=list.iterator();
		if (it.hasNext()){ //the tag was found by the query
			tag=it.next();
		}
		else tag=null;
		return tag;
	}
	
	/*
	 * is Tag Method Exist 
	 * @param tagMethodName the name of the method
	 * @return id the method exist true else return false 
	 */
	private boolean isTagMethodExist(String tagMethodName){
		boolean answer=false;
		List<String> list = getTagMethodList();
		for (String m: list){ //scan the list check each method  
			if (m.equals(tagMethodName)){
				answer=true;
				break;
			}
		}
		return answer;
	}

	/*
	 * find file by it's name
	 */
	private ClientFile findFile(String fileName) {
		// TODO Auto-generated method stub
		openSession();
		Query query = session.createQuery("from ClientFile Where file_name='"+ fileName+ "'");
		List<ClientFile> list = query.list();
		ClientFile file = new ClientFile();
		Iterator<ClientFile> it=list.iterator();
		if (it.hasNext()){ //get the file by the query
			file=it.next();
		}
		else file=null;
		return file;
		}
	
	// find the file of the tag and add him to the tag's list
	 private void findFileOfTag(String fileName,Tag tag){
		 openSession();
		Query query = session.createQuery("from ClientFile Where file_name='"+fileName+"'");
		List<ClientFile> list = query.list();
		ClientFile file = new ClientFile();
		Iterator<ClientFile> it=list.iterator();
		if (it.hasNext()){ 
			file=it.next();	//the file was found!
			if ( file.getFileName().equals(fileName)){ //add the file to the tag
				tag.getFiles().add(file);
				session.update(tag);
				session.flush();
			}
		}		
		
	}
	/**
	 * get all the file list in the Data base
	 * @return list of name of all the files in DB
	 */
	public  List<String> getFileList(){
		openSession();
		Query query = session.createQuery("from ClientFile");
		List<ClientFile> list = query.list();		
	    ArrayList<String> fileList=new ArrayList<String> ();

	    Iterator<ClientFile> it=list.iterator();
	    while (it.hasNext()){  //scan the list add all the files to file List
	    	ClientFile f=it.next();
	    	fileList.add(f.getFileName());
	    }
	    session.flush();
	   
	    return fileList;
	}
	
	/**
	 * get all the tag list in the Data base
	 * @return list of name of all the tags in DB
	 */
	public  List<String> getTagList(){
		openSession();
		Query query = session.createQuery("from Tag");
		List<Tag> list = query.list();		
	    ArrayList<String> tagList=new ArrayList<String> ();

	    Iterator<Tag> it=list.iterator();
	    while (it.hasNext()){  //scan the list add all the tags to list
	    	Tag t=it.next();
	    	tagList.add(t.getTagName());
	    }
	    session.flush();
	    
	    return tagList;
	}	
	
	/**
	* get all the tag method list in the Data base
	* @return list of tag method paths of all the method in DB
	*/
	public  List<String> getTagMethodList(){
		openSession();
		Query query = session.createQuery("from TagMethod");
		List<TagMethod> list = query.list();		
	    ArrayList<String> methodList=new ArrayList<String> ();

	    Iterator<TagMethod> it=list.iterator();
	    while (it.hasNext()){   //scan the list add all the method to list
	    	TagMethod t=it.next();
	    	methodList.add(t.getPath());
	    }
	    session.flush();
	    
	    return methodList;
	}	
}